/***************************************************************************
 *   Copyright (C) 2005 by xihe                                            *
 *   xihels@163.com                                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "QQSession.h"
#include "Unit.h"
#include "MainWindow.h"
#include <gtkmm/messagedialog.h>
#include "MsgWindow.h"
#include "UserinfoWindow.h"

#include "Packet.h"
#include "QQClient.h"
#include "Login.h"
#include "ChangeStatus.h"
#include "ClusterOperate.h"
#include "ClusterOperateReply.h"
#include "ClusterSendIM.h"
#include "DownloadGroupFriend.h"
#include "ClusterInfoReply.h"
#include "ClusterMemberInfoReply.h"
#include "FriendList.h"
#include "ReceiveIM.h"
#include <assert.h>
#include "StatusIcon.h"

QQSession::QQSession(const QQUser& user_) :
    QQClient(user_),
    msgWnd(NULL),
    currentStatus(QQ_FRIEND_STATUS_OFFLINE),
    changeStatus_(QQ_FRIEND_STATUS_OFFLINE)
{	
	mainWnd=&(GUnit::getMainWindow());
	statusIcon=new StatusIcon(mainWnd);

}

QQSession::~QQSession()
{
    delete statusIcon;
    mainWnd=NULL;
    statusIcon=NULL;
    logout();
}

void QQSession::doRecvPacket(InPacket* packet)
{
    if (!GInterface::sendMessage(this, packet))
	delete packet;
}


void QQSession::doKeepAlive(int status)
{
    if (STATUS_OK == status) { 
	// 刷新好友列表
	// 先设置所有好友为离线
	// 再发送请求在线好友的包
	friends.forEach(SetStatus(QQ_FRIEND_STATUS_OFFLINE));

	sendPacket(OutPacketPtr(new GetFriendOnlinePacket(*this)));
	// 刷新已经打开的群聊天窗口的成员列表
	if (msgWnd.get()) {
	    msgWnd->beginRefreshMembersStatus();
	}
    }
}

void QQSession::doLoginError(const LoginReplyPacket& packet)
{
    const string& str = packet.getReplyMessage();
    GUnit::getMainWindow().loginError(this, str);
}

void QQSession::doLoginOk()
{
    uint8_t status = 
	(QQ_LOGIN_MODE_NORMAL == getLoginMode()) ?
	QQ_FRIEND_STATUS_ONLINE :  
	QQ_FRIEND_STATUS_HIDDEN;

    changeStatus(status);

    if (0xffff == getFace()) { // 还不知道自己的头像，说明是第一次登录
	sendPacket(OutPacketPtr (new DownloadGroupFriendPacket(*this)));
	sendPacket(OutPacketPtr (new GetUserInfoPacket(*this, getUid())));
    } else {	    // 说明已经登录过一次，已经取得了好友列表。
	sendPacket(OutPacketPtr (new GetFriendOnlinePacket(*this, getUid())));
    }
}

void QQSession::doUnknow(const UnknowPacket& packet)
{
    switch (packet.getCommand()) {
	case QQ_CMD_CLUSTER_CMD:
	    fprintf(stderr, "Unknow Cluster command = %02x\n", packet.getUnknow()[0]);
	    return;
	default:
	    fprintf(stderr, "Unknow command = %04x\n", packet.getCommand());
    }
}

void QQSession::onChangeStatus(const ChangeStatusReplyPacket& packet)
{
    currentStatus = changeStatus_;
    GUnit::getMainWindow().refreshSelfStatus(*this);
    statusIcon->on_status_change(currentStatus/10-1,nickname);
}

void QQSession::onFriendChangeStatus(const FriendChangeStatusPacket& packet)
{
    const QQBuddyStatus& status = packet.getFriendStatus();
    Friends::value_type val = friends.getElement(status.uid);
    if (NULL == val) {
	return;
    }

    *val = status;
    GUnit::getMainWindow().refreshFriend(*this, *val);

}

void QQSession::onUserInfo(const GetUserInfoReplyPacket& packet)
{
    const QQContact* contact = packet.getContact();
    if ((0xffff == getFace()) && getUid() == packet.getUid()) {
	// 说明是最开始得到自己信息的回复包
	uint16_t face = atoi(contact->infos[21]);
	setFace(face);
	nickname = g2u.convert(contact->infos[1], strlen(contact->infos[1]));
	GUnit::getMainWindow().refreshSelfStatus(*this);
    } else {
	UserinfoWindow* wnd = 
	    new UserinfoWindow(*this, getUid() == packet.getUid());
	wnd->refreshInfo(packet);
    }
}

void QQSession::onSearchUser(const SearchUserReplyPacket& packet)
{

    const SearchUserReplyPacket::Members& members= packet.getMembers();
    for_each(members.begin(), members.end(), 
	    SetUsersList<SearchUserReplyPacket::Members>(users));
    GUnit::getMainWindow().on_SearchUser(*this);
//    fprintf(stderr, "onSearchUser()\n");
}

void QQSession::onFriendLevel(const GetFriendLevelReplyPacket& pack)
{
    //////
}

void QQSession::onFriendListPacket(const GetFriendListReplyPacket& packet)
{
    const GetFriendListReplyPacket::Members& members= packet.getMembers();

    for_each(members.begin(), members.end(), 
	    SetBuddysList<GetFriendListReplyPacket::Members>(friends));

    uint16_t pos = packet.getPosition();
    if (0xffff != pos) {
	// 请求剩下的好友名单
	if (0 == pos)
	    pos = members.size();
	sendPacket(OutPacketPtr(new GetFriendListPacket(*this, pos)));
    } else {
	// 已得到所有好友名单, 请求在线好友.
	sendPacket(OutPacketPtr(new GetFriendOnlinePacket(*this)));

	// 先请求一下自己的等级，否则腾迅会过滤部分消息。	
	GetFriendLevelPacket::Members friends;
	friends.push_back(this->getUid());
	sendPacket(OutPacketPtr(new GetFriendLevelPacket(*this, friends)));

	// 显示好友名单 
	GUnit::getMainWindow().refreshFriendsList(*this);
    }
}

void QQSession::onFriendOnlinePacket(const GetFriendOnlineReplyPacket& packet)
{
    const GetFriendOnlineReplyPacket::Members& members= packet.getMembers();

    for_each(members.begin(), members.end(), 
	    SetBuddysList<GetFriendOnlineReplyPacket::Members>(friends));

    uint8_t pos = packet.getPosition();
    if (0xff != pos) {
	if (0 == pos)
	    pos = members.size();
	sendPacket(OutPacketPtr(new GetFriendOnlinePacket(*this, pos)));
    } else {
	GUnit::getMainWindow().refreshFriendsListStatus(*this);
    }
}

void QQSession::onDownloadGroupFriend(const DownloadGroupFriendReplyPacket& packet)
{
    const DownloadGroupFriendReplyPacket::Members list = packet.getMembers();

    for_each(list.begin(), list.end(), 
	    SetGroupsList<DownloadGroupFriendReplyPacket::Members>(*this));
    if (0 != packet.getBeginFrom()) {
	sendPacket(OutPacketPtr(
		    new DownloadGroupFriendPacket(*this, packet.getBeginFrom())));
    } else 
    {
	GUnit::getMainWindow().refreshGroupsList(*this);

	sendPacket(OutPacketPtr(new GroupDataOpPacket(*this)));
	sendPacket(OutPacketPtr(new GetFriendListPacket(*this)));
	//sendPacket(OutPacketPtr(new GetFriendOnlinePacket(*this)));
    }

}
void QQSession::onGroupOpPacket(const GroupDataOpReplyPacket& packet)
{
    const GroupDataOpReplyPacket::Members& list = packet.getMembers();

    for_each(list.begin(), list.end(),
	    SetGroupsListName<GroupDataOpPacket::Members>(*this));

    GUnit::getMainWindow().refreshGroupsList(*this, REFRESH_TREEITEM);
}



void QQSession::onSendIMReply(const SendIMReplyPacket&)
{
//    printf("I am call,and my name is onSendIMReply in QQSession.cpp\n");
    //    fprintf(stderr, "reply im\n");
}

void QQSession::onClusterSendIMReply(const ClusterSendIMReplyPacket&)
{
    //    fprintf(stderr, "reply clusterIm\n");
 //   printf("I am call,and my name is onClusterSendIMReply in QQSession.cpp\n");
}

void QQSession::onNormalIM(const ReceiveIMPacket& packet)
{
    uint32_t sender = packet.getSender();
    Friends::value_type val = friends.getElement(sender);
    if (NULL == val) {
	// 先在所有群里找找，是不是群成员发过来的
	typedef const Clusters::map_type MAP_TYPE;
	MAP_TYPE& cmap = clusters.getMap();

	MAP_TYPE::const_iterator first = cmap.begin();
	MAP_TYPE::const_iterator last  = cmap.end();
	Clusters::value_type cval;
	Friends::value_type fval = NULL;
	for (; first != last; ++first) {
	    cval = static_cast<Clusters::value_type>(((*first).second));
	    if (NULL != (fval = cval->getMembers().getElement(sender))) {
		copyToFriends(fval);
		val = friends.getElement(sender);
		break;
	    }
	}
    }

    if (NULL == val) {
	val = new FriendInfo(sender, QQ_FRIEND_STATUS_ONLINE);
	val->setGroup(STRANGER_GROUP_NUM);
	friends.insertElement(sender, val);
    }

    MsgPage* page = val->getMsgPage();
    if (NULL == page) {
	page = new MsgPage(*val, *this);
	val->setMsgPage(page);
    }
    if (page->showNormalIM(packet))
	showPage(val);

}

void QQSession::onClusterIM(const ReceiveIMPacket& packet)
{
    uint32_t sender = packet.getSender();
    Clusters::value_type val = clusters.getElement(sender);
    if (NULL != val) {
	MsgPage* page = val->getMsgPage();
	if (NULL == page) {
	    page = new MsgPage(*val, *this);
	    val->setMsgPage(page);
	}
	if (page->showClusterIM(packet))
	    showPage(val);
    }
}

void QQSession::onIMPacket(const ReceiveIMPacket& packet)
{
    sendPacket(OutPacketPtr(new ReplyPacket(*this, packet.reply())));

    uint32_t sender = packet.getSender();

    switch (packet.getMessageSource()) {
	case QQ_RECV_IM_FROM_FRIEND:
	case QQ_RECV_IM_FROM_STRANGER:      /* 是从好友或者陌生人处发来的消息 */
	    onNormalIM(packet);
	    break;
	case QQ_RECV_IM_UNKNOWN_CLUSTER_IM:
	case QQ_RECV_IM_TEMP_CLUSTER_IM:
	case QQ_RECV_IM_CLUSTER_IM:
	    onClusterIM(packet);
	    break;
	case QQ_RECV_IM_SYS_MESSAGE:
		printf("some one want to add me as a friend\n");
		break;
	default:
		printf("some strange packet received\n");
		printf("%d",packet.getMessageSource());
    }
}



void QQSession::onClusterInfo(const GetClusterInfoReplyPacket& packet)
{
    uint32_t uid = packet.getUid();

    Clusters::value_type val = clusters.getElement(uid);

    if (NULL != val) {
	*val = packet;
    } else {
	val = new ClusterInfo(packet);
	clusters.insertElement(uid, val); 
    } 

    typedef GetClusterMemberInfoPacket::Members MemberList;
    const MemberList& list = packet.getMembers();

    int listsize = list.size();
    MemberList::const_iterator first = list.begin();
    while (listsize > 30) {
	sendPacket(OutPacketPtr(
		    new GetClusterMemberInfoPacket (
			*this, uid, 
			MemberList(first, first + 30
			    ))));
	first += 30;
	listsize -= 30;
    }
    if (listsize > 0) {
	sendPacket(OutPacketPtr(
		    new GetClusterMemberInfoPacket(
			*this, uid,
			MemberList(first, list.end()))));
    }

    //sendPacket(OutPacketPtr(
    //		new GetClusterOnlineMemberPacket(*this, uid)));
    GUnit::getMainWindow().refreshCluster(*this, *val);
}	

void QQSession::onClusterMember(const GetClusterMemberInfoReplyPacket& packet)
{
    uint32_t uid = packet.getUid();
    Clusters::value_type cluster = clusters.getElement(uid);

    if (NULL == cluster) {
	fprintf(stderr, "onClusterMember error\n");
	return ;
    }

    const GetClusterMemberInfoReplyPacket::Members& members 
	= packet.getMembers();
    for_each(members.begin(), members.end(),
	    SetBuddysList<GetClusterMemberInfoReplyPacket::Members>(cluster->getMembers()));

    MsgPage* msgPage = cluster->getMsgPage();
    if (msgPage) {
	msgPage->refreshMembers();
    }

}    
void QQSession::onClusterOnlineMember(const GetClusterOnlineMemberReplyPacket& packet)
{
    uint32_t uid = packet.getUid();
    Clusters::value_type cluster = clusters.getElement(uid);

    if (NULL == cluster) {
	fprintf(stderr, "onClusterMember error\n");
	return ;
    }

    const GetClusterOnlineMemberReplyPacket::Members& members 
	= packet.getMembers();
    for_each(members.begin(), members.end(),
	    SetBuddysList<GetClusterOnlineMemberReplyPacket::Members>(cluster->getMembers()));

    MsgPage* msgPage = cluster->getMsgPage();
    if (msgPage) {
	msgPage->refreshMembersStatus();
    }

}    

/////////////////////////
void QQSession::changeStatus(uint8_t status)
{
    changeStatus_ = status;;
    sendPacket(OutPacketPtr (new ChangeStatusPacket(*this, status)));
}

///////////////

void QQSession::copyToFriends(FriendInfo* friendinfo, int32_t group)
{
    g_assert(friendinfo);
    uint32_t uid = friendinfo->getUid();
    Friends::value_type val = friends.getElement(uid);

    if (NULL != val) 
	return;

    FriendInfo* tmp = new FriendInfo(*friendinfo);
    tmp->setGroup(group);
    friends.insertElement(uid, tmp);
}

/////////////////

void QQSession::showMessagePage(BuddyInfo* buddy)
{
    assert(NULL != buddy);
    MsgPage* page = buddy->getMsgPage();
    if (NULL == page) {
	page = new MsgPage(*buddy, *this);
	buddy->setMsgPage(page);
    }
    showPage(buddy, true);
}

void QQSession::showPage(BuddyInfo* buddy, bool isActive)
{
    assert(NULL != buddy);
    if (!msgWnd.get()) {
	msgWnd.reset(new MsgWindow(*this, *buddy));
    } else {
	msgWnd->showPage(*buddy, isActive);
    }
    msgWnd->show();
}


